package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

//@SpringBootApplication
public class RedisLockMain {

    public static void main(String[] args) throws InterruptedException {
        ConfigurableApplicationContext applicationContext = SpringApplication.run(RedisLockMain.class, args);

        StringRedisTemplate stringRedisTemplate = applicationContext.getBean(StringRedisTemplate.class);

        AtomicInteger count = new AtomicInteger(5);
        String sourceId = "1231231";
        int threadCount = 10;
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            final int threadId = i;
            executorService.submit(() -> {
                try {
                    String id = UUID.randomUUID().toString();
                    int tryCount = 3;
                    while (tryCount > 0) {
                        Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent(sourceId, id, 10, TimeUnit.SECONDS);
                        if (aBoolean) {
                            try {
                                if (count.get() == 0) {
                                    System.out.println("没有库存了");
                                    return;
                                }
                                count.getAndDecrement();
                                System.out.println("线程" + threadId + ":" + count.get());
                                Thread.sleep(100);
                                tryCount = 0;
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            } finally {
                                if (id.equals(stringRedisTemplate.opsForValue().get(sourceId))) {
                                    stringRedisTemplate.delete(sourceId);
                                    System.out.println("删除了锁");
                                }
                            }
                        } else {
                            System.out.println("线程" + threadId + "未获取到锁");
                            tryCount--;
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                } finally {
                    // 线程完成，计数器减1
                    countDownLatch.countDown();
                    System.out.println(countDownLatch);
                }
            });
        }

        try {
            // 注意是await();方法
            countDownLatch.await();
            System.out.println("所有线程执行完毕");
        } finally {
            System.out.println("over");
            executorService.shutdown();
            applicationContext.close();
        }
    }

    // 这只是一个demo例子，正常项目中不这么使用，
    // 另外，重试的少，并不一定保证count能到0.
}
